const express = require("express");
const path = require('path');
const util = require("./util");
const config = util.config;
const timeout = require('connect-timeout'); //express v4
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const session = require("express-session");
const getRawBody = require('raw-body');
const NedbStore = require('nedb-session-store')(session);
require('express-async-errors');

// Http 从中读取信息请求
module.exports = (app) => {
    
    /**
     * 统计请求耗时
     * 来源： 
     *      监听处理耗时 https://www.jianshu.com/p/e8cb94c84850
     *      监听响应耗时 https://www.jianshu.com/p/f0ebd8261613
     */
    app.use(function (req, res, next) {
        handlingTime = {
            start: Date.now(),
        }

        next();
        handlingTime.end = Date.now();
        res.once('finish', ()=>{
            handlingTime.finish = Date.now()
        });
        res.once('close', ()=>{
            handlingTime.close = Date.now();
            handlingTime.resTime = handlingTime.close - handlingTime.start;
            handlingTime.handTime = handlingTime.end - handlingTime.start;
            let k = (res.getHeader("content-length") / 1024).toFixed(4);
            k = isNaN(k) ? "null" : k + "k";
            try {
            console.log([
                req.method,
                req.originalUrl,
                `处理${handlingTime.handTime}ms`,
                `响应${handlingTime.resTime}ms`,
                `响应大小${k}`
            ].join(" "));
        }catch(err){
            console.error("记录请求耗时出错：", err);
        }
        });

    });
    
    // 设置跨域
    app.all("*",function(req, res, next){
        util.setCORS(req, res);
        if (req.method.toLowerCase() == 'options') res.send(200);   //让options尝试请求快速结束
        else next();
    });

    // 超时5分钟
    app.use(timeout(config.express.timeout));
    app.use(haltOnTimedout);
    function haltOnTimedout(req, res, next){
        if (!req.timedout) next();
    }

    // 数据解析
    // parse application/x-www-form-urlencoded 
    app.use(bodyParser.urlencoded({limit: config.express.urlencodedLimit, extended: true /* 是否转换成对象 */}))
    // 自定义解析函数
    // const parseJson = (req, res, buf, encoding) => {
    //     if (buf && buf.length) {
    //         let data = buf.toString();
    //         try{
    //             req.body = JSON.parse(data);
    //         }catch(err){
    //             // 如果是特殊的 json，那么转成对象并且放到属性 0 中
    //             req.body = { "0": data };
    //         }
    //     }
    // };
    const parseJson = (req, res, buf, encoding) => {
        if (buf && buf.length) {
            let data = buf.toString();
            try{
                req.body = JSON.parse(data);
            }catch(e){
                req.body = {"0": data};
                req.errOK = true;   // 标记为已处理该异常，用于处理 bodyParser.json 抛出的异常
            }
        }
    };

    // parse application/json 
    // app.use(bodyParser.json({limit: conf.express.jsonLimit, verify: parseJson }))
    app.use(bodyParser.json({ verify: parseJson, strict: false }))
    // 错误处理中间件
    app.use((err, req, res, next) => {
        if(req.errOK) {
            delete req.errOK;   // 删除标记
            next()
        } else {
            next(err)
        }
    });

    // parse cookie 
    app.use(cookieParser())
    // express session 读取方式：req.session
    app.use(session({
        secret: "334",
        name: config.sessionName,
        // 不使用本地文件存储 session 
        // store: new FileStore("./session.txt"), 
        cookie: {
            maxAge: 20 * 60 * 1000  // 一个小时
        },
        resave: false,              // 无论情况，每次都重新设置一个cookie
        // 设置为 true会增加ck的保存频率，增加服务器负担，设置为 false不会给前端设置 ck
        saveUninitialized: true,    // 即使没有被修改，也保存
        // 本地存储 session 
        store: new NedbStore({
            filename: config.rootPath + '/src/logs/nedb_file.db'
        })
    }))

    // 无 cookie拦截
    if(util.config.interceptCookie) app.use((req, res, next)=>{
        console.log("cookies:", Object.keys(req.cookies).length, req.cookies)
        next()
    });
    
    // 静态资源
    app.use('/src/res', express.static(config.rootPath + '/src/res'));

    // 全局异常捕获
    app.use((err, req, res, next)=>{
        return res.json(util.result.error("服务器错误", err));
    });
}